#include "key.h"
#include "Queue.h"


KeyType SysKey[KEY_CH_NUM];

//for test
unsigned char HardKey[KEY_CH_NUM]={0};

void KeyInit(void)
{
	//clear key ram
	unsigned int i=0;
	for(i=0;i<KEY_CH_NUM;i++)
	{
	SysKey[i].KeyCheckState=KeyCheckState_Null;
	SysKey[i].KeyPressMs=0;
	SysKey[i].KeyGapMs=0;
	}

	//init key mess queue
	Queue_Init();
	//ClearKeyQueue
	Queue_Clear(&SysKeyQueueBuffer);
}
//for test
unsigned char KeySetHardKey(unsigned char ch,unsigned char key)
{
	HardKey[ch]=key;
}
unsigned char KeyGetHardKey(unsigned char ch)
{
	//read io 
	return HardKey[ch];
}
KeyPressStateType KeyGetPressState(unsigned char ch)
{
	unsigned char keyVal=0;

	//get key press state from hardware
	keyVal=KeyGetHardKey(ch);

	if(keyVal==0){
		return KeyPress_On;
	}
	else{
		return KeyPress_Off;
	}
}

static void Key_Check_Ch(unsigned int ch)
{
	unsigned short KeyChCode=0;//KeyCh+KeyCode
	KeyPressStateType keyPressState=KeyGetPressState(ch);
	KeyType *pSysKey=&SysKey[ch];
	//no key press
	if(pSysKey->KeyCheckState==KeyCheckState_Null)
	{
		if(keyPressState==KeyPress_On){
			pSysKey->KeyCheckState=KeyCheckState_Chatter;
		}
		else{
		
		}
	}
	//chatter
	else if(pSysKey->KeyCheckState==KeyCheckState_Chatter)
	{
		if(keyPressState==KeyPress_On){
			pSysKey->KeyPressMs+=KEY_CHECK_CYC_MS;
		}
		else{
			pSysKey->KeyPressMs=0;
			pSysKey->KeyPressMs=KeyCheckState_Null;
		}	

		if(pSysKey->KeyPressMs>=KEY_CHATTER_MS){
			pSysKey->KeyCheckState=KeyCheckState_Press;
			pSysKey->KeyPressMs=0;
		}
		else{}
	}
	//key press on ms cnt
	else if(pSysKey->KeyCheckState==KeyCheckState_Press)
	{
		//press on ms cnt
		if(keyPressState==KeyPress_On){
			pSysKey->KeyPressMs+=KEY_CHECK_CYC_MS;
		}
		else{
			pSysKey->KeyCheckState=KeyCheckState_Done;
		}

		//now is long click & previous click is short & the gap is in double gap betwen previous and now 
		//->deal the previus as short click,now is long click
		if((pSysKey->KeyPressMs>=KEY_LONG_MS)&&(pSysKey->KeyGapMs>0)&&(pSysKey->KeyGapMs<KEY_DOUBLE_GAP_MS))
		{
			//Send Signle Key  To Queue
			KeyChCode=ch;
			KeyChCode<<=8;
			KeyChCode+=KeyVal_Single;
			Queue_Push(&SysKeyQueueBuffer,KeyChCode);
			pSysKey->KeyPressMs=0;
			pSysKey->KeyGapMs=0;		
		}
	}
	else if(pSysKey->KeyCheckState==KeyCheckState_Done)
	{
		//long click check
		if(pSysKey->KeyPressMs>=KEY_LONG_MS)
		{
			//Send Long Key To Queue
			KeyChCode=ch;
			KeyChCode<<=8;
			KeyChCode+=KeyVal_Long;
			Queue_Push(&SysKeyQueueBuffer,KeyChCode);
			pSysKey->KeyPressMs=0;
			pSysKey->KeyGapMs=0;
			pSysKey->KeyCheckState=KeyCheckState_Null;

		}
		else//signle or double click check deal
		{
			if((pSysKey->KeyGapMs>0)&&(pSysKey->KeyGapMs<KEY_DOUBLE_GAP_MS))
			{
				//Send Double Key to queue
				KeyChCode=ch;
				KeyChCode<<=8;
				KeyChCode+=KeyVal_Double;
				Queue_Push(&SysKeyQueueBuffer,KeyChCode);
				pSysKey->KeyPressMs=0;
				pSysKey->KeyCheckState=KeyCheckState_Null;
				pSysKey->KeyGapMs=0;
			}
			else
			{
				pSysKey->KeyCheckState=KeyCheckState_WaitDouble;
			}
		}
	}
	else if(pSysKey->KeyCheckState==KeyCheckState_WaitDouble)
	{
		if(keyPressState==KeyPress_On){
			pSysKey->KeyCheckState=KeyCheckState_Null;
			pSysKey->KeyPressMs=0;
		}
		else{
			pSysKey->KeyGapMs+=KEY_CHECK_CYC_MS;
		}

		//the gap delay ms betwen now signle and last signle click >double gap delay ms
		if(pSysKey->KeyGapMs>=KEY_DOUBLE_GAP_MS)
		{
			//Send Signle key message to queue
			KeyChCode=ch;
			KeyChCode<<=8;
			KeyChCode+=KeyVal_Single;
			Queue_Push(&SysKeyQueueBuffer,KeyChCode);
			pSysKey->KeyPressMs=0;
			pSysKey->KeyGapMs=0;
			pSysKey->KeyCheckState=KeyCheckState_Null;
		}
		else{}
	}
	else{}
}

void Key_Check_Cyc(void)
{
	unsigned int i=0;
	for(i=0;i<KEY_CH_NUM;i++)
	{
		Key_Check_Ch(i);
	}
}